package com.tencent.elife.view;

import android.content.Context;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.BounceInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.Scroller;

import com.tencent.elife.utils.L;

/**
 * @Description: 从侧面滑动展开的布局容器, 支持从左右两个方向展开
 * 1.必须有且仅有两个子布局，而且有顺序要求，第一个是固定不动的view，第二个是要滑动的view
 * 2.可以在XML文件中指定如下自定义字段： 
 * animDurition: 展开动画的持续时间
 * animType:滑动的动画效果，0是减速效果也是默认的，1是回弹效果，2是线性下拉 
 * orientation:固定view所占的位置，left固定的view在左边，right固定的view在右边，默认在右边
 * @author zijianlu
 * @date 2012-6-4
 */

public class SlideFrame extends FrameLayout {
    private static final String TAG = "elife.slideframe";

    private Scroller mScroller;
    private int mChildCount = 0;
    private View mSlidingView;
    private View mFixedView;

    private int mSlideWidth = 0;
    private int mTotalWidth = 0;
    private int mTotalHeight = 0;
    private int mCurSlideWidth = 0;

    private boolean isSizeSet = false;
    private boolean isExpand = false;
    private boolean isFixedViewRight = true;

    private int mAnimDurition = 0;

    private OnSlideListener mOnSlideListener = null;

    public SlideFrame(Context context, AttributeSet attrs) {
        super(context, attrs);

        mAnimDurition = attrs.getAttributeIntValue(null, "animDurition", 300);
        int animType = attrs.getAttributeIntValue(null, "animType", 0);
        String orientation = attrs.getAttributeValue(null, "orientation");
        if (!TextUtils.isEmpty(orientation)
            && orientation.equalsIgnoreCase("left")) {
            isFixedViewRight = false;
        }

        Interpolator interpolator = null;
        switch (animType) {
        case 0:
            interpolator = new DecelerateInterpolator();
            break;

        case 1:
            interpolator = new BounceInterpolator();
            break;

        case 2:
            interpolator = new LinearInterpolator();
            break;

        default:
            interpolator = new DecelerateInterpolator();
            break;
        }

        mScroller = new Scroller(context, interpolator);

        ViewConfiguration vc = new ViewConfiguration();
        mSlop = vc.getScaledEdgeSlop();

    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mChildCount = getChildCount();
        if (mChildCount != 2) {
            throw new RuntimeException("should have two child views~~");
        }

        mFixedView = getChildAt(0);
        mSlidingView = getChildAt(1);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (!isSizeSet) {
            mTotalWidth = mSlidingView.getMeasuredWidth();
            mTotalHeight = mSlidingView.getMeasuredHeight();
            mSlideWidth = mFixedView.getMeasuredWidth();

            if (mSlideWidth > mTotalWidth) {
                mSlideWidth = mTotalWidth;
            }

            L.D(TAG, "mSlideWidth:" + mSlideWidth + " total:" + mTotalWidth);
            isSizeSet = true;
        }
        setMeasuredDimension(mTotalWidth, mTotalHeight);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
        int bottom) {

        if (isFixedViewRight) {
            mSlidingView.layout(0, 0, (mTotalWidth - mCurSlideWidth),
                mTotalHeight);
            mFixedView.layout(mTotalWidth - mSlideWidth, 0, mTotalWidth,
                mTotalHeight);

            mSlidingView.scrollTo(mCurSlideWidth, 0);
        } else {
            mSlidingView.layout(mCurSlideWidth, 0, mTotalWidth, mTotalHeight);
            mFixedView.layout(0, 0, mSlideWidth, mTotalHeight);
        }

        if (mCurSlideWidth == mSlideWidth) {
            isExpand = true;
            if (mOnSlideListener != null) {
                mOnSlideListener.onSlide(true);
            }
        } else if (mCurSlideWidth == 0) {
            isExpand = false;
            if (mOnSlideListener != null) {
                mOnSlideListener.onSlide(false);
            }
        }

        L.D(TAG, "onLayout mCurSlideWidth:" + mCurSlideWidth + " "
            + (mTotalWidth - mSlideWidth));
    }

    /** 展开 */
    public void slide() {
        if (!isExpand) {
            mScroller.forceFinished(true);
            mScroller.startScroll(0, 0, mSlideWidth, 0, mAnimDurition);
            invalidate();
        }
    }

    /** 收拢 */
    public void unSlide() {
        if (isExpand) {
            mScroller.forceFinished(true);
            mScroller.startScroll(mSlideWidth, 0, -mSlideWidth, 0,
                mAnimDurition);
            invalidate();

        }
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            mCurSlideWidth = mScroller.getCurrX();
            L.D(TAG, "computeScroll mCurSlideWidth:" + mCurSlideWidth + " "
                + mSlidingView.getScrollX());
            requestLayout();
            invalidate();
        }
    }

    /** 监听展开和收缩的监听器 */
    public void setOnSlideListener(OnSlideListener onSlideListener) {
        mOnSlideListener = onSlideListener;
    }

    public interface OnSlideListener {
        public void onSlide(boolean isExpanded);
    }

    /************************ 触屏事件处理处理 ************************/
    private int mSlop = 0;
    private int mLastX = 0;
    private int mDownX = 0;
    private boolean isValidEvent = true;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            return true;
        }

        return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int action = event.getAction();

        if (isExpand) {
            Rect rect = new Rect();
            mFixedView.getHitRect(rect);
            if (action == MotionEvent.ACTION_DOWN) {
                if (mCurSlideWidth == mSlideWidth
                    && rect.contains((int) event.getX(), (int) event.getY())) {
                    isValidEvent = false;
                } else {
                    isValidEvent = true;
                }
            }
        } else {
            isValidEvent = true;
        }

        if (!isValidEvent) {
            return super.dispatchTouchEvent(event);
        }

        switch (action) {
        case MotionEvent.ACTION_DOWN: {
            mDownX = (int) event.getX();
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            int x2 = (int) event.getX();
            int disX = 0;
            if (mLastX == 0) {
                disX = x2 - mDownX;
            } else {
                disX = x2 - mLastX;
            }
            mLastX = x2;

            if (Math.abs(x2 - mDownX) > mSlop) {
                event.setAction(MotionEvent.ACTION_CANCEL);
            }

            if (isFixedViewRight) {
                mCurSlideWidth -= disX;
                // 固定view在右边
                if (disX > 0) {
                    // 往右滑
                    if (mCurSlideWidth < 0) {
                        mCurSlideWidth = 0;
                    }
                } else {
                    // 往左滑
                    if (mCurSlideWidth > mSlideWidth) {
                        mCurSlideWidth = mSlideWidth;
                    }
                }
                requestLayout();
            } else {
                mCurSlideWidth += disX;
                // 固定view在左边
                if (disX > 0) {
                    // 往右滑
                    if (mCurSlideWidth > mSlideWidth) {
                        mCurSlideWidth = mSlideWidth;
                    }
                } else {
                    // 往左滑
                    if (mCurSlideWidth < 0) {
                        mCurSlideWidth = 0;
                    }
                }
                requestLayout();
            }

            break;
        }
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL: {
            mDownX = 0;
            mLastX = 0;

            mScroller.forceFinished(true);
            if (mCurSlideWidth < mSlideWidth * 0.5) {
                mScroller.startScroll(mCurSlideWidth, 0, -mCurSlideWidth, 0,
                    mAnimDurition / 2);
            } else {
                mScroller.startScroll(mCurSlideWidth, 0, mSlideWidth
                    - mCurSlideWidth, 0, mAnimDurition / 2);
            }
            invalidate();

            break;
        }
        }
        return super.dispatchTouchEvent(event);
    }
}